
#pragma once
#include <windows.h>
#include <d3d9.h> 
#include <d3dx9.h>

#include <vector>
#include <string>
#include "config.h"

#include "..\..\CommLib\PacketConven.h"
typedef unsigned int uint;

#define GRID_RESOULTION 10
#define GRIDVERTEX_COUNT ((GRID_RESOULTION + 1) * 2 * 2)

#define READ_PROCEDURAL(type, dataPtr) type(*(type*)dataPtr); dataPtr += sizeof(type);

struct tInstanceChild;
struct tPart;
class Render {

public:
	static const UINT	STREAMOUT_MAX = 1024 * 50;
	static const UINT	INSTANCE_STRIDE = sizeof(float) * 8;

	enum DeviceVersion {
		D3D_9,
		D3D_10
	};

	enum ResourceType {
		VERTEX_BUFFER = 0,
		INDEX_BUFFER = 2,
		TEXTURE = 1,
	};

	struct tResource {
		
		LPVOID			pResource;
		std::string		filename;
		ResourceType	type;
#pragma message ("--assign this for all")
	};

	struct tShader{ 

		friend class Render;
	private:
		uint			referenceCount;
	public:
		tShader();
		LPVOID			pEffect;
		LPVOID			pInputDeclaration;
		std::string		filename;
		uint			VertexFormat;
		uint			Attributes;

		void Print();
	};

protected:

	static Render::tResource* g_pVertexBuffer_Grid;
	static Render::tShader* g_pGridShader;
	static Render::tShader* g_pDefaultShader;
	static Render::tResource* g_pProceduralBaseData;

	static std::vector<Render::tResource*>	g_Resources;
	static std::vector<Render::tShader*>	g_Shaders;

	virtual u_int UpdateShaderRefCount(Render::tShader* pShader, int delta);

	DeviceVersion m_Version;
	
	static struct tCamera { 
		D3DXMATRIX m_View;
		D3DXMATRIX m_Proj;

		float m_Angles[2];

		D3DXVECTOR3 m_Forward;
		D3DXVECTOR3 m_Right;
		D3DXVECTOR3 m_Position;
	} g_Camera;


	static const char* samplers[SAMPLE_COUNT];
	static const char* vertex_elements[VERTEX_ELEMENT_COUNT];
	static const char* channels[CHANNEL_COUNT];

	static bool GetPrecached(const std::string& filename, const uint VertexFormat, const uint Attributes, Render::tShader** pInOut);
	const static std::string SHADER_DIRECTORY;
public:


	
	virtual bool GetShader(const std::string& filename, const uint VertexFormat, const uint Attributes, Render::tShader** pInOut = NULL, bool forceReload = true, LPVOID pTargetDevice = NULL) = 0;
	virtual bool ReleaseShader(Render::tShader** pShader) = 0;

	static DeviceVersion g_lastVersion;
	static Render* Singleton(DeviceVersion version = g_lastVersion);

	static bool GetDefaultShader(const uint VertexFormat, Render::tShader** pOut);
	static bool ShadersEqual(Render::tShader* pA, Render::tShader* pB);
	static bool ShadersEqual(Render::tShader* pA, std::string filenameB, uint VertexFormatB, uint AttributesB);

	virtual void SetShaderTexture(DWORD Stage,tResource* pTexture) = 0;
	void SetCameraProjection(float fovRadians, float aspectRatio, float nearPlane, float farPlane);
	void SetCameraPositionDirection(D3DXVECTOR3& position, D3DXVECTOR3& direction);
	void SetCameraFrameNavigation(D3DXVECTOR3& velocity, float yaw, float pitch);
	void GetCameraViewProjection(D3DXMATRIX* pViewProjection);

	virtual bool Create(HWND hWnd) = 0;
	virtual bool Release() = 0;
	virtual bool ReloadResources() = 0;

	virtual bool CreateVertexBuffer(UINT sizeBytes, bool isStreamOut, tResource** pInOut) = 0;
	virtual bool CreateIndexBuffer(UINT sizeBytes, tResource** pInOut) = 0;
	virtual bool CreateVertexIndicieBuffer(UINT sizeBytes,LPVOID pData, uint vertexFormat, tResource** pVBOut, tResource** pIBOut) = 0;
	virtual bool FillVertexBuffer(tResource* pVertexBuffer, UINT sizeInBytes, LPVOID pData) = 0;
	virtual bool BindVertexBuffer(tResource** pVertexBuffers, UINT* elementSizes, UINT BufferCount) = 0;
	virtual bool BindIndexBuffer(tResource* pIndexBuffer, UINT elementSize) = 0;
	virtual bool BindStreamOutBuffer(tResource* pStreamOutBuffer, UINT elementSize) = 0;
	virtual bool DrawIndexedTriangleList(UINT triangelCount, UINT* pInstanceCount, UINT *pDeformationPass) = 0;
	virtual bool DrawTriangleList(UINT elementCount, UINT* pInstanceCount) = 0;
	virtual bool DrawLineList(UINT elementCount) = 0;
	virtual bool CreateTexture(const std::string& filename, Render::tResource** pOut = NULL, LPVOID pDevice = NULL) = 0;
	virtual bool GetTexture(const std::string& filename, Render::tResource** pOut = NULL) = 0;
	virtual bool ReleaseResource(tResource** pResource) = 0;
	//virtual bool StreamOutToBuffer(tPart* pParentMesh, D3DXMATRIX* pWorld,Render::tResource* pInstanceBuffer, uint* pPrimitvesWritten) = 0;
	virtual bool StreamOutToBuffer(tPart* pParentMesh, Render::tResource* pCookie, int uvChannel,D3DXMATRIX* pWorld, tInstanceChild* pChild,uint* pPrimitvesWritten) = 0;
	virtual bool BeginShader(const Render::tShader* pShader, bool isInstanced, UINT* pPasses) = 0;
	virtual bool EndShader() = 0;

	virtual bool SetShaderMatrix(LPCSTR pName, D3DXMATRIX* pValue) = 0;
	virtual bool SetShaderVector(LPCSTR pName, D3DXVECTOR4* pValue) = 0;
	virtual bool SetShaderFloat(LPCSTR pName, float value) = 0;
	virtual bool SetShaderInt(LPCSTR pName, int value) = 0;

	virtual bool BeginShaderPass(UINT pass) = 0;
	virtual bool EndShaderPass() = 0;

	void DrawGrid();
	void ShowGrid(const bool visible);

	virtual bool BeginSprites() = 0;
	virtual bool EndSprites() = 0;
	virtual void DrawSprite(tResource* pTexture, D3DXVECTOR2& position, D3DXVECTOR2& scale, RECT* pSrc) = 0;
	virtual void DrawString(DWORD type, D3DCOLOR color, D3DXVECTOR2& position, char* format, ...) = 0;

	virtual bool GetTextureInfo(tResource* pTexture, UINT* pWidth, UINT* pHeight) = 0;
	virtual bool GetBufferInfo(tResource* pBuffer, UINT* pSizeInBytes) = 0;

	virtual void BeginRendering() = 0;
	virtual void EndRendering() = 0;
	
	/*virtual bool StreamOutBuffer(Model* pParentMesh, Render::tResource* pInstanceBuffer, UINT* pPrimitvesWritten) = 0;*/
};